package org.jdcenter.jmx.mx4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;

import mx4j.tools.adaptor.http.HttpAdaptor;
import mx4j.tools.adaptor.http.XSLTProcessor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdcenter.face.JMXManager;

public class JMXManagerMX4JImpl implements JMXManager{
	
	protected Log log = LogFactory.getLog(getClass());
	
	private int port = 8080;

	private String host = "localhost";

	private String path = null;
	
	private String pathInJar = null;
	
	ObjectName httpAdaptorName = null;
	
	private static MBeanServer server = MBeanServerFactory.createMBeanServer("jdstream");
	
	public JMXManagerMX4JImpl(){
	}
	
	public JMXManagerMX4JImpl(int port,String host){
		this.port = port;
		this.host = host;
	}
	
	public JMXManagerMX4JImpl(int port,String host,String path,String pathInJar){
		this.port = port;
		this.host = host;
		this.path = path;
		this.pathInJar = pathInJar;
	}
	
	protected MBeanServer getServer(){
		if(server == null){
			server = MBeanServerFactory.createMBeanServer("jdstream");
		}
		return server;
	}
	
	public ObjectInstance registerMBean(String objName,Object mBean) throws MalformedObjectNameException, NullPointerException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException{
		ObjectName name = new ObjectName(objName);
		return getServer().registerMBean(mBean, name);
	}
	
	public ObjectInstance registerMBean(ObjectName objName,Object mBean) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException{
		return getServer().registerMBean(mBean, objName);
	}
	
	public void regsiterAndStartMBean(String objName,Object mBean) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, NullPointerException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		registerAndStartMBean(objName,mBean,"start");		
	}
	
	public void registerAndStartMBean(ObjectName objName,Object mBean) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		registerAndStartMBean(objName,mBean,"start");
	}
	
	public void registerAndStartMBean(String objName,Object mBean,String startMethod) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, NullPointerException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		ObjectName name = new ObjectName(objName);
		registerAndStartMBean(name,mBean,startMethod);		
	}
	
	public void registerAndStartMBean(ObjectName objName,Object mBean,String startMethod) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		registerMBean(objName,mBean);
		boolean flag = true;
		Method start = null;
		try {
			start = mBean.getClass().getDeclaredMethod(startMethod, new Class[0]);
		} catch (SecurityException e) {
			flag = false;
			log.error(e);
		} catch (NoSuchMethodException e) {
			flag = false;
			log.error(e);
		}
		if(flag && start != null){
			start.setAccessible(true);
			start.invoke(mBean, new Object[0]);
		}
	}
	
	public void removeMBean(String objName) throws MalformedObjectNameException, NullPointerException, InstanceNotFoundException, IntrospectionException, ReflectionException, MBeanException{
		removeMBean(new ObjectName(objName));
	}
	
	public void removeMBean(ObjectName objName) throws InstanceNotFoundException, IntrospectionException, ReflectionException, MBeanException{
		removeMBean(objName,"stop");
	}
	
	public void removeMBean(String objName,String stopMethod) throws MalformedObjectNameException, NullPointerException, InstanceNotFoundException, IntrospectionException, ReflectionException, MBeanException{
		removeMBean(new ObjectName(objName),stopMethod);
	}
	
	public void removeMBean(ObjectName objName,String stopMethod) throws InstanceNotFoundException, IntrospectionException, ReflectionException, MBeanException{
		MBeanInfo mBean = getServer().getMBeanInfo(objName);
		MBeanOperationInfo[] mBeanInfos = mBean.getOperations();
		for(MBeanOperationInfo info:mBeanInfos){
			if(info.getName().equals(stopMethod)){
				getServer().invoke(objName, stopMethod, null, null);
				break;
			}
		}
		getServer().unregisterMBean(objName);
	}
	
	public void setAttribute(ObjectName objName,Attribute attribute) throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException{
		getServer().setAttribute(objName, attribute);
	}
	
	public void setAttributes(ObjectName objName,AttributeList attributes) throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException{
		getServer().setAttributes(objName, attributes);
	}
	
	public void invoke(ObjectName objName,String operationName,Object[] params,String[] signature) throws InstanceNotFoundException, MBeanException, ReflectionException{
		getServer().invoke(objName, operationName, params, signature);
	}
	
	public void start() throws MalformedObjectNameException, NullPointerException, InstanceAlreadyExistsException, NotCompliantMBeanException, InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException{
		log.info("start JMXManager");
		httpAdaptorName = new ObjectName("Http:name=HttpAdapter");
		HttpAdaptor httpAdaptor = new HttpAdaptor();
		registerMBean(httpAdaptorName,httpAdaptor);
		if(port > 0){
			setAttribute(httpAdaptorName, new Attribute("Port",new Integer(port)));
		}
		if(host != null){
			setAttribute(httpAdaptorName,new Attribute("Host",host));
		}
		log.info("HttpAdaptor listen at "+host+":"+port);
		ObjectName processorName = new ObjectName("Http:name=XSLTProcessor");
		XSLTProcessor processor = new XSLTProcessor();
		registerMBean(processorName,processor);
		if(path != null){
			setAttribute(processorName, new Attribute("File",path));
		}
		if(pathInJar != null){
			setAttribute(processorName, new Attribute("PathInJar",pathInJar));
		}
		setAttribute(httpAdaptorName, new Attribute("ProcessorName",processorName));
		invoke(httpAdaptorName, "start", null, null);
	}
	
	public void stop() throws InstanceNotFoundException, MBeanException, ReflectionException{
		invoke(httpAdaptorName, "stop", null, null);
	}
	
	public void dispose(){
		
	}

}
